#include "entity.h"
#include "button.h"
#include "images_diffuse.h"
#include "graphics.h"
#include "bullet.h"
#include "tag.h"
#include "explosions.h"
#include "hitbox.h"
#include "util.h"
#include "warp.h"
#include "sounds.h"

declare_body(player_particle, {
	size_t lifetime;
	size_t current_lifetime;
})

declare_tick(player_particle, {
	if(--self->current_lifetime == 0) return 1;
})

declare_draw(player_particle, {
	float opacity = self->current_lifetime / (float)self->lifetime;
	draw_sprite_a(&sprite_player_engine_particle, parent->position.x - 10.5f, parent->position.y - 18, opacity);
})

declare_head(player_particle)

void new_player_particle(vec pos) {
	entity *ent = ent_new();
	ent->position = pos;
	ent->tag = TAG_BACKGROUND_PARTICLE;
	
	player_particle *pp = c_new(player_particle);
	pp->lifetime = 8;
	pp->current_lifetime = 8;
	
	add_component(ent, pp);
}

static joystick controls;

struct player;
int player_do_warp_cycle = 0;

typedef void (*gun_function)(struct player*,entity*);

declare_body(player, {
	vec velocity;
	sprite_renderer *renderer;
	size_t bullet_cooldown;
	gun_function gun;
})

void gun_basic(player *self, entity *parent) {
	make_player_bullet(
		get_animator_c(&sprite_player_basic_bullet, 1, vxy(0, 5)),
		vsub(parent->position, vxy(0.5f, 0)),
		vxy(0.f, 5.f),
		laser_explosion
	);
	self->bullet_cooldown = 10;
}

void gun_triple(player *self, entity *parent) {
	make_player_bullet(
		get_animator_c(&sprite_player_basic_bullet, 1, vxy(0, 5)),
		vsub(parent->position, vxy(0.5f + 2.f, 0)),
		vxy(-0.2f, 5.f),
		laser_explosion
	);
	make_player_bullet(
		get_animator_c(&sprite_player_basic_bullet, 1, vxy(0, 5)),
		vsub(parent->position, vxy(0.5f, 0)),
		vxy(0.f, 6.f),
		laser_explosion
	);
	make_player_bullet(
		get_animator_c(&sprite_player_basic_bullet, 1, vxy(0, 5)),
		vsub(parent->position, vxy(0.5f - 2.f, 0)),
		vxy(0.2f, 5.f),
		laser_explosion
	);
	self->bullet_cooldown = 10;
}

void gun_cycle(player *self, entity *parent) {
	make_player_cycle_bullet(
		vsub(parent->position, vxy(0.5f, 0)),
		vxy(0.f, 1.f),
		NULL
	);
	self->bullet_cooldown = 15;
}

void gun_missile(player *self, entity *parent) {
	make_player_missile_bullet(
		vsub(parent->position, vxy(0.5f, 0)),
		vxy(0.f, 5.f),
		NULL,
		6
	);
	self->bullet_cooldown = 20;
}

declare_tick(player, {
	if(player_do_warp_cycle) {
		if(parent->visible) {
			vec target = vxy(100.5f, 70);
			parent->position = vadd(parent->position, vmul(vsub(target, parent->position), 0.1f));
			if(len2(vsub(parent->position, target)) < 0.5f) {
				parent->visible = 0;
				player_warp_animation();
				play_sound(s_warp);
			}
		}
	}
	else {
	
		vec vel_target = vmul(joystick_value(controls), 2 + warp_fac() * 2);
		
		self->velocity = vadd(self->velocity, vmul(vsub(vel_target, self->velocity), 0.1f));
		
		parent->position = vadd(parent->position, self->velocity);
	}
	
	int frame = 0;
	if(self->velocity.x < -0.6f) frame = 1;
	if(self->velocity.x > 0.6f) frame = 2;
	
	fclamp(&parent->position.y, -20, 170);
	
	if(parent->visible) {
		if(self->bullet_cooldown) --self->bullet_cooldown;
		if(get_key(' ')->is_down) {
			if(!self->bullet_cooldown) {
				self->gun(self, parent);
				play_sound(s_player_shoot);
			}
		}
		else {
			self->bullet_cooldown = 0;
		}
	}
	
	
	
	self->renderer->frame = frame;
	if(parent->visible)
		new_player_particle(parent->position);
	
	
})

declare_draw(player, { })

declare_head(player)

gun_function guns[] = {
	&gun_triple,
	&gun_cycle,
	&gun_missile
};

void player_load_weapon(entity *target, int index) {
	player *p = get_component(target, player);
	if(!p) return;
	
	if(index == -1) p->gun = &gun_basic;
	else {
		p->gun = guns[index];
	}
}

entity *make_player() {
	entity *ent = ent_new();
	ent->tag = TAG_PLAYER;
	
	player_reset(ent);
	
	controls = joystick_from(key_axis('A', 'D'), key_axis('S', 'W'));
	return ent;
}

void player_reset(entity *target) {
	clear_components(target);
	
	player *p = c_new(player);
	sprite_renderer *r = get_animator_c(&sprite_player_ship, 0, vxy(10.5f, 18));
	r->animate = 0;
	p->renderer = r;
	p->bullet_cooldown = 0;
	p->gun = &gun_basic;
	
	add_component(target, r);
	add_component(target, p);
	
	add_hitbox(target, -3.5f, -8, 7, 5);
	
	for(int i = 7; i >= -11; --i) {
		if(i <= 0 && i >= -11) {
			add_hitpoint(target, vxy(-7.5f, i));
			add_hitpoint(target, vxy(7.5f, i));
		}
		if(i <= 7 && i >= -9) {
			add_hitpoint(target, vxy(0, i));
		}
		if(i <= -5 && i >= -11) {
			add_hitpoint(target, vxy(-2.5f, i));
			add_hitpoint(target, vxy(2.5f, i));
		}
	}
}